import { addLoop, addVertex, babylonToVEMesh, addEdge, addFace, VEMeshToBabylon } from "../operation";
import { VEEdge, VEFace, VELoop, VEVertex } from "./";

export class VEMesh {

  /**
   * 所有面元素数组
   */
  public faces = new Array<VEFace>();

  /**
   * 所有顶点元素数组
   */
  public vertices = new Array<VEVertex>();

  /**
   * 所有边元素数组，具有唯一性
   */
  public edges = new Array<VEEdge>();

  /**
   * 所有loop半边元素数组
   */
  public loops = new Array<VELoop>();


  public constructor() {
  }

  /**
   * 将babylon mesh结构转化为VEMesh结构
   * @param mesh 原始babylon mesh网格
   * @param tolerance 
   */
  public babylonToVEMesh(mesh: BABYLON.AbstractMesh, tolerance: number = 1e-10) {
    babylonToVEMesh(this, mesh, tolerance);
  }

  public VEMeshToBabylon(mesh: BABYLON.Mesh,
    tolerance: number = 1e-10): void {
    if (mesh) {
      mesh.dispose();
      VEMeshToBabylon(this, mesh, tolerance);
    }
  }

  public VEMeshToNewBabylon(scene: BABYLON.Scene, name: string, tolerance: number = 1e-10): BABYLON.Mesh {
    const newMesh = new BABYLON.Mesh(name, scene);
    VEMeshToBabylon(this, newMesh, tolerance);
    return newMesh;
  }


  public clear(): void {
    this.faces.clear();
    this.vertices.clear();
    this.edges.clear();
    this.loops.clear();
    // TODO：新建序号reset
    VEVertex.start();
    VEFace.start();
  }

  /**
   * 添加顶点数据
   * @param position 位置坐标
   * @param checkDuplicates 去除坐标冗余的点，保持坐标唯一性，默认：true
   * @param tolerance 坐标值对比参考
   * @returns 
   */
  public addVertex(
    position: BABYLON.Vector3,
    normal: BABYLON.Vector3,
    checkDuplicates = true,
    tolerance = 1e-10) {
    return addVertex(this, position, normal, checkDuplicates, tolerance);
  }

  public addEdge(v1: VEVertex, v2: VEVertex) {
    return addEdge(this, v1, v2)
  }

  public addLoop(v1: VEVertex, v2: VEVertex, e1: VEEdge, allowParallels = false) {
    return addLoop(this, v1, v2, e1, allowParallels)
  }

  public addFace(loops: VELoop[]) {
    return addFace(this, loops);
  }


  public allLoops() {
    const loops = new Array<VELoop>();

    const handled = new Set<VELoop>();

    for (const loop of this.loops) {
      if (!handled.has(loop)) {

        for (const he of loop.nextLoop()) {
          handled.add(he);
        }
        loops.push(loop);
      }
    }
    return loops;
  }

}